package com.doupi.partner.api.controller;

import com.doupi.partner.api.core.AbstractBiz;
import com.doupi.partner.api.core.ApiRequest;
import com.doupi.partner.api.core.ApiResponse;
import com.doupi.partner.util.*;
import com.doupi.partner.util.constant.UtilConstants;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.MDC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * API统一入口
 */
@Controller
public class EntranceController {
	private static final Logger LOGGER = LoggerFactory.getLogger(EntranceController.class);
	// 请求用户 %X{USER}
	private static final String LOGGER_USER = "USER";

	// 请求接口 %X{BIZ}
	private static final String LOGGER_BIZ = "BIZ";

	// 请求IP %X{IP}
	private static final String LOGGER_IP = "IP";

	// 参数biz为空消息提示
	private static final String NO_BIZ_PARAMETER_MESSAGE = "biz：业务参数不能为空";

	// 参数biz不正确消息提示
	private static final String WRONG_BIZ_VALUE_MESSAGE = "biz：参数值错误，请联系管理员";

	private final JwtUtils jwtUtils;

	@Autowired
	public EntranceController(JwtUtils jwtUtils) {
		super();
		this.jwtUtils = jwtUtils;
	}

	@ResponseBody
	// TODO 测试
	@CrossOrigin("*")
	@RequestMapping(value = "entrance", method = RequestMethod.POST)
	public Object dispatcherControl(HttpServletRequest httpRequest, @RequestBody ApiRequest request) {
		// 封装请求
		request = wrapRequest(httpRequest, request);

		// 获取业务实现
		AbstractBiz biz = SpringContextUtils.getBeanByName(request.getBiz());

		// 执行业务，并catch业务异常
		ApiResponse response = ApiResponse.defaultResponse();
		try {
			Assert.notNull(biz, WRONG_BIZ_VALUE_MESSAGE);
			biz.doExecute(request, response);
		} catch (RuntimeBusinessException e) {
			response.setStatusCodeAndMessage(e.getCode(), e.getMessage());
		} catch (Throwable e) {
			LOGGER.error("系统响应失败", e);
			response.setStatusCodeAndMessage(UtilConstants.FAIL_STATUS_CODE, e.getMessage());
		}

		// 封装响应
		return wrapResponse(response, request);
	}

	// 封装request
	private ApiRequest wrapRequest(HttpServletRequest httpRequest, ApiRequest request) {
		// 业务不能为空
		AssertUtils.assertNotBlank(request.getBiz(), NO_BIZ_PARAMETER_MESSAGE);

		// 业务参数合法，只能是英文字母
		AssertUtils.isTrue(RegexUtils.isEnglish(request.getBiz()), WRONG_BIZ_VALUE_MESSAGE);

		request.setIp(HttpRequestUtils.getClientIp(httpRequest));

		if (StringUtils.isNotBlank(request.getToken())) {
			// TODO 只放用户id，还是放对象 ？
			Object jwtData = jwtUtils.parse(request.getToken());
			request.setJwt(jwtData);
		}

		// 设置logback日志打印参数
		MDC.put(LOGGER_USER, request.getJwt());
		MDC.put(LOGGER_BIZ, request.getBiz());
		MDC.put(LOGGER_IP, request.getIp());

		LOGGER.info("请求数据：{}", request);
		return request;
	}

	// 封装response
	private ApiResponse wrapResponse(ApiResponse response, ApiRequest apiRequest) {
		// 统一响应参数
		response.setBiz(apiRequest.getBiz());
		response.setPlatform(apiRequest.getPlatform());
		response.setResponseTime(new Date());

		// TODO 响应内容过多不打印
		// LOGGER.info("响应数据：{}", response);
		return response;
	}
}
